//
//  Info.h
//  OpenGLGame
//
//  Created by Nguyen Cong Huy on 11/22/12.
//  Copyright (c) 2012 UIT. All rights reserved.
//

#ifndef OpenGLGame_Info_h
#define OpenGLGame_Info_h

/** 
 
 
 NOTE : 
 - LBGraphics:
 Graphics must be:
 call setDefaultFrameBuffer() in GLKView: drawInRect: 
 call setScreenSizeAndViewportOfRealDevice() in init ViewController.
 
 - LBFlter:
 + To create a derived class of LBFilter, example LBDerivedFilter. In LBDerivedFilter.h, define variables for new parametters, and new attributes/uniforms for those parametters. Also, create setter and getter function define for that parametters. 
 + In LBDerivedFilter.mm, create constructor, call init(...) with new shader, and get attributes/uniforms index in those constructor. With each setters, set value for each parametter and send value to shader program use glUniform... or glVertexAttribPointer and glEnableVertexAttribArray.
 + Have to setTexture before addTarget.
 
 */

/**
 SOME USEFUL FUNCTION:
 
 // safe color
 "float safeColorF(float color){"
 "    if(color > 1.0) color = 1.0;"
 "    else if(color < 0.0) color = 0.0;"
 "    return color;"
 "}"
 
 "vec4 safeColor(vec4 color){"
 "    color.r = safeColorF(color.r);"
 "    color.g = safeColorF(color.g);"
 "    color.b = safeColorF(color.b);"
 "    return color;"
 "}"
 // END safe color
 
 //saturation function (default 1.0)
 "vec4 saturationColor(vec4 color, float saturation){"
 "  float avg = (color.r + color.g + color.b)/3.0; "
 "  color.r = avg + saturation*(color.r - avg); "
 "  color.g = avg + saturation*(color.g - avg);"
 "  color.b = avg + saturation*(color.b - avg);"
 "   color = clamp(color, 0.0, 1.0);"
 "  return color;"
 "}"
 //END saturation function
 
 //contrast function (default 1.0)
 "vec4 contrastColor(vec4 color, float contrast){"
 "  color.r = (color.r - 0.5)*contrast + 0.5;"
 "  color.g = (color.g - 0.5)*contrast + 0.5;"
 "  color.b = (color.b - 0.5)*contrast + 0.5;"
 "  color = clamp(color, 0.0, 1.0);"
 "  return color;"
 "}"
 //END contrast function
 
 //multiply function
 "vec4 multiplyColor(vec4 color1, vec4 color2){"
 "color1.r = (color1.r * color2.r);"
 "color1.g = (color1.g * color2.g);"
 "color1.b = (color1.b * color2.b);"
 "color1 = clamp(color1, 0.0, 1.0);"
 "return color1;"
 "}"
 //END multiply function
 
 //tin effect function
 "vec4 tintEffect(vec4 color, float rMax, float gMax, float bMax, float rMin, float gMin, float bMin){"
 "  color.r = (color.r - rMin)*(1.0/(rMax - rMin));"
 "  color.g = (color.g - gMin)*(1.0/(gMax - gMin));"
 "  color.b = (color.b - bMin)*(1.0/(bMax - bMin));"
 "  color = clamp(color, 0.0, 1.0);"
 "  return color;"
 "}"
 //END tin effect function
 
 //brightness function (default 0.0)
 "  vec4 brightnessColor(vec4 color, float brightness){"
 "  color.r = color.r + brightness;"
 "  color.g = color.g + brightness;"
 "  color.b = color.b + brightness;"
 "  color = clamp(color, 0.0, 1.0);"
 "  return color;"
 "}"
 //END brightness function
 
 //brightness function float (default 0.0)
 "vec4 brightnessColorF(vec4 color, float brightnessR, float brightnessG, float brightnessB){"
 "  color.r = color.r + brightnessR;"
 "  color.g = color.g + brightnessG;"
 "  color.b = color.b + brightnessB;"
 "  color = clamp(color, 0.0, 1.0);"
 "  return color;"
 "}"
 //END brightness function
 
 // exclusion function
 "vec4 exclusion(vec4 base, vec4 blend, float opacity){"
 "   vec4 result =  base;"
 
 "   result.r = 0.5 - 2.0* (base.r - 0.5)*(blend.r - 0.5);"
 "   result.g = 0.5 - 2.0* (base.g - 0.5)*(blend.g - 0.5);"
 "   result.b = 0.5 - 2.0* (base.b - 0.5)*(blend.b - 0.5);"
 
 "   result = mix(base, result, opacity);"
 
 "   return result;"
 
 "}"
 // END exclusion function
 
 // soft light function (opacity equal 1/2 value in photoshop)
 "vec4 softLight(vec4 base, vec4 blend, float opacity){"
 "   vec4 white = vec4(1.0, 1.0, 1.0, 1.0);"
 "   vec4 lumCoeff = vec4(0.2125, 0.7154, 0.0721, 1.0);"
 "   vec4 result;"
 
 "   float luminance = dot(base, lumCoeff);"
 "   if (luminance < 0.45)"
 "       result = 2.0 * blend * base;"
 "   else if (luminance > 0.55)"
 "       result = white - 2.0 * (white - blend) * (white - base);"
 "   else"
 "   {"
 "       vec4 result1 = 2.0 * blend * base;"
 "       vec4 result2 = white - 2.0 * (white - blend) * (white - base);"
 "       result = mix(result1, result2, (luminance - 0.45) * 10.0);"
 "   }"
 "    result = mix(base, result, opacity);"
 "   return result;"
 "}"
 // END soft light function
 
 // hard light blend function
 "vec4 hardLight(vec4 base, vec4 blend, float opacity){"
 "   vec4 result =  base;"
 "    if (blend.r > 0.5) result.r = 1.0 - (1.0-base.r) *(1.0-2.0*(blend.r-0.5));"
 "    else result.r = base.r * (2.0*blend.r);"
 
 "    if (blend.g > 0.5) result.g = 1.0 - (1.0-base.g) *(1.0-2.0*(blend.g-0.5));"
 "    else result.g = base.g * (2.0*blend.g);"
 
 "    if (blend.b > 0.5) result.b = 1.0 - (1.0-base.b) *(1.0-2.0*(blend.b-0.5));"
 "    else result.b = base.b * (2.0*blend.b);"
 
 "    result = mix(base, result, opacity);"
 "    return result;"
 "}"
 // END hard light blend function
 
 // linear light function
 "vec4 linearLight(vec4 base, vec4 blend, float opacity){"
 "   vec4 result = base;"
 "   if (blend.r > 0.5) result.r = base.r + 2.0*(blend.r-0.5);"
 "   else result.r = base.r + 2.0*blend.r - 1.0;"
 "   if (blend.g > 0.5) result.g = base.g + 2.0*(blend.g-0.5);"
 "   else result.g = base.r + 2.0*blend.r - 1.0;"
 "   if (blend.r > 0.5) result.b = base.r + 2.0*(blend.r-0.5);"
 "   else result.b = base.r + 2.0*blend.r - 1.0;"
 "   result = mix(base, result, opacity);"
 "   result = clamp(result, 0.0, 1.0);"
 "   return result;"
 "}"
 // END linear light function
 
 // radial gradient color function
 "vec4 radialGradientColor(vec4 centerColor, vec4 outerColor, vec2 myPosition, vec2 centerPosition){"
 "    float distance = clamp(distance(myPosition, centerPosition), 0.0, 1.0);"
 "    return mix(centerColor, outerColor, distance);"
 "}"
 // radial gradient color function
 
 // overlay function
 "vec4 overlay(vec4 base, vec4 blend, float opacity){"
 "   vec4 white = vec4(1.0, 1.0, 1.0, 1.0);"
 "   vec4 lumCoeff = vec4(0.2125, 0.7154, 0.0721, 1.0);"
 "   float luminance = dot(base, lumCoeff);"
 "   vec4 result;"
 "   if (luminance < 0.45)"
 "       result = 2.0 * blend * base;"
 "   else if (luminance > 0.55)"
 "       result = white - 2.0 * (white - blend) * (white - base);"
 "   else"
 "   {"
 "       vec4 result1 = 2.0 * blend * base;"
 "       vec4 result2 = white - 2.0 * (white - blend) * (white - base);"
 "       result = mix(result1, result2, (luminance - 0.45) * 10.0);"
 "   }"
 "   result = mix(base, result, opacity);"
 "   return result;"
 "}"
 // END overlay function
 
 // hue function
 "vec4 hueColor(vec4 color, float hueAdjust){"
 "   float PI = 3.141592654;"
 "   hueAdjust = hueAdjust*PI/180.0;"
 
 "   const highp  vec4  kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);"
 "   const highp  vec4  kRGBToI     = vec4 (0.595716, -0.274453, -0.321263, 0.0);"
 "   const highp  vec4  kRGBToQ     = vec4 (0.211456, -0.522591, 0.31135, 0.0);"
 
 "   const highp  vec4  kYIQToR   = vec4 (1.0, 0.9563, 0.6210, 0.0);"
 "   const highp  vec4  kYIQToG   = vec4 (1.0, -0.2721, -0.6474, 0.0);"
 "   const highp  vec4  kYIQToB   = vec4 (1.0, -1.1070, 1.7046, 0.0);"
 
 // Convert to YIQ
 "   highp float   YPrime  = dot (color, kRGBToYPrime);"
 "   highp float   I      = dot (color, kRGBToI);"
 "   highp float   Q      = dot (color, kRGBToQ);"
 
 // Calculate the hue and chroma
 "   highp float   hue     = atan (Q, I);"
 "   highp float   chroma  = sqrt (I * I + Q * Q);"
 
 // Make the user's adjustments
 "   hue += (hueAdjust);" //why negative rotation?
 
 // Convert back to YIQ
 "   Q = chroma * sin (hue);"
 "   I = chroma * cos (hue);"
 
 // Convert back to RGB
 "   highp vec4    yIQ   = vec4 (YPrime, I, Q, 0.0);"
 "   color.r = dot (yIQ, kYIQToR);"
 "   color.g = dot (yIQ, kYIQToG);"
 "   color.b = dot (yIQ, kYIQToB);"
 
 // Save the result
 "   return color;"
 "}"
 // END hue function
 
 // function need for "blend saturation function"
 "vec3 RGBToHSL(vec3 color)"
 "{"
 "    vec3 hsl;"
 
 "    float fmin = min(min(color.r, color.g), color.b);   "
 "    float fmax = max(max(color.r, color.g), color.b); "
 "    float delta = fmax - fmin;             "
 
 "    hsl.z = (fmax + fmin) / 2.0;    "
 "    if (delta == 0.0)"
 "    {"
 "        hsl.x = 0.0;"
 "        hsl.y = 0.0;"
 "    }"
 "    else{"
 "        if (hsl.z < 0.5)"
 "            hsl.y = delta / (fmax + fmin);"
 "        else"
 "            hsl.y = delta / (2.0 - fmax - fmin);"
 
 "        float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;"
 "        float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;"
 "        float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;"
 
 "        if (color.r == fmax )"
 "        hsl.x = deltaB - deltaG;"
 "        else if (color.g == fmax)"
 "            hsl.x = (1.0 / 3.0) + deltaR - deltaB;"
 "        else if (color.b == fmax)"
 "            hsl.x = (2.0 / 3.0) + deltaG - deltaR;        "
 "        if (hsl.x < 0.0)"
 "            hsl.x += 1.0;"
 "        else if (hsl.x > 1.0)"
 "            hsl.x -= 1.0;"
 "    }"
 
 "    return hsl;"
 "}"
 
 "float HueToRGB(float f1, float f2, float hue)"
 "{"
 "	if (hue < 0.0)"
 "		hue += 1.0;"
 "	else if (hue > 1.0)"
 "		hue -= 1.0;"
 "	float res;"
 "	if ((6.0 * hue) < 1.0)"
 "		res = f1 + (f2 - f1) * 6.0 * hue;"
 "	else if ((2.0 * hue) < 1.0)"
 "		res = f2;"
 "	else if ((3.0 * hue) < 2.0)"
 "		res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;"
 "	else"
 "		res = f1;"
 "	return res;"
 "}"
 
 "vec3 HSLToRGB(vec3 hsl)"
 "{"
 "    vec3 rgb;"
 
 "    if (hsl.y == 0.0)"
 "        rgb = vec3(hsl.z);"
 "    else"
 "    {"
 "        float f2;"
 
 "        if (hsl.z < 0.5)"
 "            f2 = hsl.z * (1.0 + hsl.y);"
 "        else"
 "            f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);"
 
 "        float f1 = 2.0 * hsl.z - f2;"
 
 "        rgb.r = HueToRGB(f1, f2, hsl.x + (1.0/3.0));"
 "        rgb.g = HueToRGB(f1, f2, hsl.x);"
 "        rgb.b= HueToRGB(f1, f2, hsl.x - (1.0/3.0));"
 "    }"
 
 "    return rgb;"
 "}"
 // END function need for "blend saturation function"
 
 // blend saturation function, require RGBToHSL() and HSLToRGB() function
 "vec4 blendSaturation(vec4 base, vec4 blend, float opacity)"
 "{"
 "    vec3 baseHSL = RGBToHSL(base.rgb);"
 "    vec4 result = vec4(HSLToRGB(vec3(baseHSL.r, RGBToHSL(blend.rgb).g, baseHSL.b)), base.a);"
 "   return mix(base, result, opacity);"
 "}"
 // END blend saturation
 
 // level function
 "vec4 gammaCorrection(vec4 color, float gamma){"
 "    vec4 result = pow(color, vec4(1.0 / gamma));"
 "    result.a = color.a;"
 "    return result;"
 "}"
 
 "vec4 levelsControlInputRange(vec4 color, float minInput, float maxInput){"
 "    vec4 result = min(max(color - vec4(minInput), vec4(0.0)) / (vec4(maxInput) - vec4(minInput)), vec4(1.0));"
 "   result.a = color.a;"
 "   return result;"
 "}"
 
 "vec4 levelsControlInput(vec4 color, float minInput, float gamma, float maxInput){"
 "    return gammaCorrection(levelsControlInputRange(color, minInput, maxInput), gamma);"
 "}"
 
 "vec4 levelsControlOutputRange(vec4  color, float minOutput, float maxOutput){"
 "    vec4 result =  mix(vec4(minOutput), vec4(maxOutput), color);"
 "    result.a = color.a;"
 "    return result;"
 "}"
 
 "vec4 levelsControl(vec4 color, float minInput, float gamma, float maxInput, float minOutput, float maxOutput){"
 " 	vec4 result = levelsControlOutputRange(levelsControlInput(color, minInput, gamma, maxInput), minOutput, maxOutput);"
 "   return result;"
 "}"
 
 // END level function
 
 // divide function
 "vec4 divide(vec4 base, vec4 blend, float opacity){"
 "   mediump float ra;"
 "   if (blend.a == 0.0 || ((base.r / blend.r) > (base.a / blend.a)))"
 "       ra = blend.a * base.a + blend.r * (1.0 - base.a) + base.r * (1.0 - blend.a);"
 "   else"
 "       ra = (base.r * blend.a * blend.a) / blend.r + blend.r * (1.0 - base.a) + base.r * (1.0 - blend.a);"
 
 
 "   mediump float ga;"
 "   if (blend.a == 0.0 || ((base.g / blend.g) > (base.a / blend.a)))"
 "       ga = blend.a * base.a + blend.g * (1.0 - base.a) + base.g * (1.0 - blend.a);"
 "   else"
 "       ga = (base.g * blend.a * blend.a) / blend.g + blend.g * (1.0 - base.a) + base.g * (1.0 - blend.a);"
 
 
 "   mediump float ba;"
 "   if (blend.a == 0.0 || ((base.b / blend.b) > (base.a / blend.a)))"
 "       ba = blend.a * base.a + blend.b * (1.0 - base.a) + base.b * (1.0 - blend.a);"
 "   else"
 "       ba = (base.b * blend.a * blend.a) / blend.b + blend.b * (1.0 - base.a) + base.b * (1.0 - blend.a);"
 
 "   mediump float a = blend.a + base.a - blend.a * base.a;"
 
 "   vec4 result = vec4(ra, ga, ba, a);"
 
 "    result = mix(base, result, opacity);"
 "    return result;"
 "}"
 // END divide function
 
 // lighten function
 "vec4 lighten(vec4 base, vec4 blend, float opacity){"
 "   vec4 result = max(base, blend);"
 "   result = mix(base, result, opacity);"
 "   return result;"
 "}"
 // END lighten function
 
 // vignette function
 "vec4 vignette(vec4 color, vec4 vignetteColor, vec2 center, highp float begin, highp float end, float intensity, vec2 texCoor){"
 "   float d = distance(texCoor, vec2(center.x, center.y));"
 "   float percent = smoothstep(begin, end, d) * intensity;"
 "   vec4 result = vec4(mix(color.r, vignetteColor.x, percent), mix(color.y, vignetteColor.y, percent), mix(color.z, vignetteColor.z, percent), 1.0);"
 "   return result;"
 "}"
 // END vignette function
 
 // exposure function
 "vec4 exposure(vec4 color, float expo){"
 "   vec4 result = vec4(color.rgb * pow(2.0, expo), color.a);"
 "   return result;"
 "}"
 // END exposure function
 
 //function colorOffset
 "vec4 colorOffset(vec4 color, vec4 offset){"
 "   color = color + offset;"
 "   return color;"
 "}"
 // END function colorOffset
 
 // function whiteBalance
 "vec4 whiteBalance(vec4 color, float temperature, float tint){"
 "   const mediump mat3 RGBtoYIQ = mat3(0.299, 0.587, 0.114, 0.596, -0.274, -0.322, 0.212, -0.523, 0.311);"
 "   const mediump mat3 YIQtoRGB = mat3(1.0, 0.956, 0.621, 1.0, -0.272, -0.647, 1.0, -1.105, 1.702);"
 "   const mediump vec3 warmFilter = vec3(0.93, 0.54, 0.0);"
 
 "   if(temperature < 5000.0) temperature = 0.0004 * (temperature - 5000.0);"
 "   else temperature = 0.00006 * (temperature - 5000.0);"
 
 "	mediump vec3 yiq = RGBtoYIQ * color.rgb;"
 "	yiq.b = clamp(yiq.b + tint*0.5226*0.1, -0.5226, 0.5226);"
 "	lowp vec3 rgb = YIQtoRGB * yiq;"
 
 "	vec3 processed = vec3("
 "                              (rgb.r < 0.5 ? (2.0 * rgb.r * warmFilter.r) : (1.0 - 2.0 * (1.0 - rgb.r) * (1.0 - warmFilter.r))), "
 "                              (rgb.g < 0.5 ? (2.0 * rgb.g * warmFilter.g) : (1.0 - 2.0 * (1.0 - rgb.g) * (1.0 - warmFilter.g))), "
 "                              (rgb.b < 0.5 ? (2.0 * rgb.b * warmFilter.b) : (1.0 - 2.0 * (1.0 - rgb.b) * (1.0 - warmFilter.b))));"
 
 
 "    vec4 result = vec4(mix(rgb, processed, temperature), color.a);"
 "    return result;"
 "}"
 // END function whiteBalance
 
 // function colorMatrix
 "vec4 colorMatrix(vec4 color, mat4 matrix, vec4 colorOffset, float intensity){"
 "   vec4 result = color * matrix;"
 
 "   result.r += colorOffset.r;"
 "   result.g += colorOffset.g;"
 "   result.b += colorOffset.b;"
 "   result.a += colorOffset.a;"
 
 "   result = mix(result, color, intensity);"
 "   return result;"
 "}"
 // END function colorMatrix
 
 // DEFAULT SHADER
 
 // default shader of two input image
 char twoInputVerShaderStr[] = ""
 
 "attribute vec4 position;"
 "attribute vec4 texCoor;"
 "uniform mat4 mWorld;"
 "uniform mat4 mProjection;"
 
 "varying vec2 vtexCoor;"
 "varying vec4 vposition;"
 
 "varying vec2 vtexCoor2;"
 "attribute vec4 texCoor2;"
 
 "void main()"
 "{"
 "    gl_Position = mProjection * mWorld * position;"
 "    vtexCoor = texCoor.xy;"
 "    vtexCoor2 = texCoor2.xy;"
 "   vposition = gl_Position;"
 "}";
 
 char twoInputFragShaderStr[] = ""
 "precision highp float;"
 
 "varying highp vec2 vtexCoor;"
 "uniform sampler2D texture;"
 
  "varying highp vec2 vtexCoor2;"
 "uniform sampler2D texture2; "
 
 "void main()"
 "{"
 "    lowp vec4 textureColor = texture2D(texture, vtexCoor);"
 "    lowp vec4 texture2Color = texture2D(texture2, vtexCoor2);"
 "    gl_FragColor = textureColor;"
 "}";
 // END default shader of two input image
 
 */

#endif
